<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Writing Modules</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="index.html" title="GnomeVFS - Filesystem Abstraction library">
<link rel="up" href="modules.html" title="Filesystem Modules">
<link rel="prev" href="modules.html" title="Filesystem Modules">
<link rel="next" href="gnome-vfs-2.0-gnome-vfs-method.html" title="gnome-vfs-method">
<meta name="generator" content="GTK-Doc V1.15.1 (XML mode)">
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"><tr valign="middle">
<td><a accesskey="p" href="modules.html"><img src="left.png" width="24" height="24" border="0" alt="Prev"></a></td>
<td><a accesskey="u" href="modules.html"><img src="up.png" width="24" height="24" border="0" alt="Up"></a></td>
<td><a accesskey="h" href="index.html"><img src="home.png" width="24" height="24" border="0" alt="Home"></a></td>
<th width="100%" align="center">GnomeVFS - Filesystem Abstraction library</th>
<td><a accesskey="n" href="gnome-vfs-2.0-gnome-vfs-method.html"><img src="right.png" width="24" height="24" border="0" alt="Next"></a></td>
</tr></table>
<div class="refentry">
<a name="gnome-vfs-writing-modules"></a><div class="titlepage"></div>
<div class="refnamediv"><table width="100%"><tr>
<td valign="top">
<h2><span class="refentrytitle">Writing Modules</span></h2>
<p>Writing Modules — basic gnome-vfs module concepts</p>
</td>
<td valign="top" align="right"></td>
</tr></table></div>
<div class="refsect1">
<a name="Introduction"></a><h2>Introduction</h2>
<p>This section will introduce the basic concepts that are
      needed for writing GNOME Virtual File System modules.</p>
<div class="refsect2">
<a name="uris"></a><h3>GNOME VFS URIs (Uniform Resource Identifiers)</h3>
<p>The GNOME Virtual file system uses URIs similiar to the
        standard WWW URIs.  The basic difference between a VFS URI and
        WWW URI is that, while with WWW URIs you can only use a single
        protocol for accessing a certain file, with GNOME VFS URIs you
        can combine different access methods in sequence.</p>
<p>For example, suppose you want to access file
        <code class="filename">hello.c</code> in a <code class="filename">tar.gz</code>
        file which is in turn accessible through FTP from a remote
        machine.  In order to access this file, you would need to:</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem"><p>Connect to the FTP site.</p></li>
<li class="listitem"><p>Fetch the <code class="filename">tar.gz</code>
        file.</p></li>
<li class="listitem"><p>Decompress the <code class="filename">tar.gz</code> file using
          GZIP.</p></li>
<li class="listitem"><p>Extract <code class="filename">hello.c</code> from the resulting
          uncompressed <code class="filename">tar</code> file.</p></li>
</ol></div>
<p>The GNOME Virtual File System lets you express this by
        combining the three access methods (i.e. tar, GZIP and FTP)
        into a single URI.  Access methods are combined in the URI by
        using the `#' character, followed by the name for the access
        method and the subpath for that specific access method.  The
        subpath can be omitted for those storage methods that do not
        need a path to retrieve the file.  (For example, a GZIP file
        always contains a single uncompressed file, so no path is
        needed to locate the uncompressed file within the GZIP file.
        But on the other hand, the TAR method requires a path to
        locate a specific file or directory.)</p>
<p>For example, in the case we outlined above, the URI would
        look something like:</p>
<pre class="programlisting">

        ftp://username:password@host.net/path/to/file.tar.gz#gzip:#tar:/path/to/hello.c</pre>
<p>Each method/subpath couple is called a <em class="firstterm">URI
      element</em>.  When URI elements are combined like this,
      each URI element uses the previous one to access a base resource
      into which it will look up a file, using the subpath
      information.  For this reason, we will say that each element is
      the <em class="firstterm">parent</em> element for the following one.</p>
<p>The first URI element, the one which has no parent, is
      called the <em class="firstterm">toplevel element</em>.  It does not
      use the `#' character; instead, it uses the standard syntax of
      WWW URIs: </p>
<pre class="programlisting">

        method://user:password@host/path/to/file</pre>
<p>This way, normal WWW URIs can be used with the GNOME Virtual
      File System.</p>
<p>Toplevel elements are also special because they let users
        specify user names, passwords and host names, while
        non-toplevel elements don't.</p>
</div>
<hr>
<div class="refsect2">
<a name="id2765933"></a><h3>The <span class="structname">GnomeVFSURI</span> type</h3>
<p>Within the GNOME Virtual File System library, URI elements
      are represented by a special type,
      <span class="structname">GnomeVFSURI</span>, which is meant to represent
      user-provided URIs in a machine-optimized way.  </p>
<p>Every <span class="structname">GnomeVFSURI</span> contains the
      following information:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem"><p>A reference counter</p></li>
<li class="listitem"><p>A pointer to the parent
        <span class="structname">GnomeVFSURI</span> URI element.</p></li>
<li class="listitem"><p>The subpath.</p></li>
<li class="listitem"><p>The name of the access method.</p></li>
<li class="listitem"><p>A pointer to a
        <span class="structname">GnomeVFSMethod</span> object, describing the
        access method (see below).</p></li>
</ul></div>
</div>
</div>
<div class="refsect1">
<a name="id2765998"></a><h2>GNOME Virtual File System access method implementation</h2>
<p>In the GNOME Virtual File System, the implementations for
    all the access methods are loaded at runtime, as shared library
    modules.  The modules are loaded during parsing of the string URI.
    If the parser encounters an access method for which no
    implementation is currently loaded, it retrieves the corresponding
    library file, dynamically links it into the executable, and
    initializes it.</p>
<p>After initialization, the module returns a special
    <span class="structname">GnomeVFSMethod</span> object that contains
    pointers to the various implementation functions for that specific
    method.  By storing a pointer to this object into the
    <span class="structname">GnomeVFSURI</span> type, the VFS library is then
    able to use these functions for file access.</p>
<div class="refsect2">
<a name="id2766030"></a><h3>How file access is performed</h3>
<p>When the VFS library needs to perform some file operation,
      it performs the following steps:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem"><p>If the URI is given in textual form (i.e. as a
        string), it parses it and activates the necessary access method
        modules.</p></li>
<li class="listitem"><p>It retrieves a pointer to the lowmost
        level URI element.</p></li>
<li class="listitem"><p>It retrieves a pointer to the
        <span class="structname">GnomeVFSMethod</span> object that corresponds
        to the access method for that URI element.</p></li>
<li class="listitem"><p>It retrieves a pointer to the implementation
        function for that operation from the
        <span class="structname">GnomeVFSMethod</span>object.</p></li>
<li class="listitem"><p>It invokes that implementation function
        passing the pointer to the lowmost level URI
        element.</p></li>
</ul></div>
<p>Combining the access methods is always done within the
      method implementation.  If the method implementation needs to do
      some file operation on the the parent URI element, it can do so
      by simply invoking the corresponding VFS function, by using
      the parent pointer in the <span class="structname">GnomeVFSURI</span>
      object. </p>
<p>For example, suppose you have to read a simple URI like
      the following:</p>
<pre class="programlisting">

        file:/home/ettore/file.gz#gzip:</pre>
<p>In this case, the GZIP method will be invoked with a
      pointer to the <span class="structname">GnomeVFSURI</span> describing the
      `gzip' part. The GZIP method will be able to read
      <code class="filename">file.gz</code> by just invoking the corresponding
      GNOME VFS library function on its parent and decompressing it on
      the fly. </p>
</div>
</div>
<div class="refsect1">
<a name="id2766129"></a><h2>Implementing an access method in practice</h2>
<p>Implementing a new access method is really not difficult at
    all.  This section explains how this is done.</p>
<div class="refsect2">
<a name="id2766141"></a><h3>Using shared libraries</h3>
<p>Every module must be compiled as a shared library (i.e. a
      <code class="filename">.so</code> file).</p>
<p>The current way for accessing the right module for the
      right method is very simple, and is based on file names.  In
      practice, a module implementing an access method named
      <code class="filename">foo</code> must be named
      <code class="filename">libfoo.so</code>.  For example, the module
      implementing the <code class="filename">ftp:</code> access method is
      called <code class="filename">libftp.so</code>, the module implementing
      <code class="filename">#gzip:</code> access is called
      <code class="filename">libgzip.so</code> and so on.</p>
<p>This might change in the future.</p>
</div>
<hr>
<div class="refsect2">
<a name="id2766206"></a><h3>The initialization/shutdown functions</h3>
<p>Every shared library module must provide two functions:</p>
<pre class="programlisting">

GnomeVFSMethod *vfs_module_init (const char *method_name, const char *args);
void vfs_module_shutdown (GnomeVFSMethod *method);</pre>
<p>These are the only functions that the VFS library will
      access directly.  All the other symbols (i.e. functions and
      variables) in the module should be made static. </p>
<p><code class="function">vfs_module_init()</code> is called
      as soon as the module is loaded in memory.  It will have to
      return a pointer to a <span class="structname">GnomeVFSMethod</span>
      object that will contain the pointers to the method's
      implementation functions.  We will describe this later. </p>
<p><code class="function">vfs_module_shutdown</code>, instead,
      is called before the module is unloaded or the program that uses
      it dies.  This functions should:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem"><p>Deallocate all the memory allocated by the
        module.</p></li>
<li class="listitem"><p>Close all the file descriptors associated with
        the module.</p></li>
<li class="listitem"><p>Kill any external process spawned by the
        module.</p></li>
<li class="listitem"><p>In general, make sure that any operation that
        was going on before this function was called will be
        interrupted correctly, as soon as possible and without any
        leaks.</p></li>
</ul></div>
</div>
<hr>
<div class="refsect2">
<a name="id2766286"></a><h3>The <span class="structname">GnomeVFSMethod</span> object</h3>
<p>This object contains pointers to the module
      implementation functions.</p>
<p>A method can choose itself which functions to implement. However, it
      must at least provide a <span class="type">GnomeVFSMethodOpenFunc</span> and
      <span class="type">GnomeVFSMethodIsLocalFunc</span> implementation.</p>
<pre class="programlisting">
struct GnomeVFSMethod {
	gsize method_table_size;			/* Used for versioning */
	GnomeVFSMethodOpenFunc open;
	GnomeVFSMethodCreateFunc create;
	GnomeVFSMethodCloseFunc close;
	GnomeVFSMethodReadFunc read;
	GnomeVFSMethodWriteFunc write;
	GnomeVFSMethodSeekFunc seek;
	GnomeVFSMethodTellFunc tell;
	GnomeVFSMethodTruncateHandleFunc truncate_handle;
	GnomeVFSMethodOpenDirectoryFunc open_directory;
	GnomeVFSMethodCloseDirectoryFunc close_directory;
	GnomeVFSMethodReadDirectoryFunc read_directory;
	GnomeVFSMethodGetFileInfoFunc get_file_info;
	GnomeVFSMethodGetFileInfoFromHandleFunc get_file_info_from_handle;
	GnomeVFSMethodIsLocalFunc is_local;
	GnomeVFSMethodMakeDirectoryFunc make_directory;
	GnomeVFSMethodRemoveDirectoryFunc remove_directory;
	GnomeVFSMethodMoveFunc move;
	GnomeVFSMethodUnlinkFunc unlink;
	GnomeVFSMethodCheckSameFSFunc check_same_fs;
	GnomeVFSMethodSetFileInfo set_file_info;
	GnomeVFSMethodTruncateFunc truncate;
	GnomeVFSMethodFindDirectoryFunc find_directory;
	GnomeVFSMethodCreateSymbolicLinkFunc create_symbolic_link;
	GnomeVFSMethodMonitorAddFunc monitor_add;
	GnomeVFSMethodMonitorCancelFunc monitor_cancel;
	GnomeVFSMethodFileControlFunc file_control;
	GnomeVFSMethodForgetCacheFunc forget_cache;
	GnomeVFSMethodGetVolumeFreeSpaceFunc get_volume_free_space;
};
</pre>
<pre class="programlisting">
typedef GnomeVFSResult (* GnomeVFSMethodOpenFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle
			       	 	**method_handle_return,
					 GnomeVFSURI *uri,
					 GnomeVFSOpenMode mode,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodCreateFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle
			       	 	**method_handle_return,
					 GnomeVFSURI *uri,
					 GnomeVFSOpenMode mode,
					 gboolean exclusive,
					 guint perm,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodCloseFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodReadFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 gpointer buffer,
					 GnomeVFSFileSize num_bytes,
					 GnomeVFSFileSize *bytes_read_return,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodWriteFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 gconstpointer buffer,
					 GnomeVFSFileSize num_bytes,
					 GnomeVFSFileSize *bytes_written_return,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodSeekFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSSeekPosition  whence,
					 GnomeVFSFileOffset    offset,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodTellFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSFileSize *offset_return);

typedef GnomeVFSResult (* GnomeVFSMethodOpenDirectoryFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle **method_handle,
					 GnomeVFSURI *uri,
					 GnomeVFSFileInfoOptions options,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodCloseDirectoryFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodReadDirectoryFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSFileInfo *file_info,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodGetFileInfoFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *uri,
					 GnomeVFSFileInfo *file_info,
					 GnomeVFSFileInfoOptions options,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodGetFileInfoFromHandleFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSFileInfo *file_info,
					 GnomeVFSFileInfoOptions options,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodTruncateFunc) (GnomeVFSMethod *method,
						       GnomeVFSURI *uri,
						       GnomeVFSFileSize length,
						       GnomeVFSContext *context);
typedef GnomeVFSResult (* GnomeVFSMethodTruncateHandleFunc) (GnomeVFSMethod *method,
							     GnomeVFSMethodHandle *handle,
							     GnomeVFSFileSize length,
							     GnomeVFSContext *context);

typedef gboolean       (* GnomeVFSMethodIsLocalFunc)
					(GnomeVFSMethod *method,
					 const GnomeVFSURI *uri);

typedef GnomeVFSResult (* GnomeVFSMethodMakeDirectoryFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *uri,
					 guint perm,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodFindDirectoryFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *find_near_uri,
					 GnomeVFSFindDirectoryKind kind,
					 GnomeVFSURI **result_uri,
					 gboolean create_if_needed,
					 gboolean find_if_needed,
					 guint perm,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodRemoveDirectoryFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *uri,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodMoveFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *old_uri,
					 GnomeVFSURI *new_uri,
					 gboolean force_replace,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodUnlinkFunc)
                                        (GnomeVFSMethod *method,
					 GnomeVFSURI *uri,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodCheckSameFSFunc)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *a,
					 GnomeVFSURI *b,
					 gboolean *same_fs_return,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodSetFileInfo)
					(GnomeVFSMethod *method,
					 GnomeVFSURI *a,
					 const GnomeVFSFileInfo *info,
					 GnomeVFSSetFileInfoMask mask,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodCreateSymbolicLinkFunc)
                                        (GnomeVFSMethod *method,
                                         GnomeVFSURI *uri,
                                         const gchar *target_reference,
                                         GnomeVFSContext *context);
typedef GnomeVFSResult (* GnomeVFSMethodMonitorAddFunc)
     					(GnomeVFSMethod *method,
      					 GnomeVFSMethodHandle **method_handle_return,
      					 GnomeVFSURI *uri,
      					 GnomeVFSMonitorType monitor_type);

typedef GnomeVFSResult (* GnomeVFSMethodMonitorCancelFunc)
     					(GnomeVFSMethod *method,
      					 GnomeVFSMethodHandle *handle);

typedef GnomeVFSResult (* GnomeVFSMethodFileControlFunc)
     					(GnomeVFSMethod *method,
      					 GnomeVFSMethodHandle *method_handle,
					 const char *operation,
					 gpointer operation_data,
					 GnomeVFSContext *context);

typedef GnomeVFSResult (* GnomeVFSMethodForgetCacheFunc)
     					(GnomeVFSMethod *method,
      					 GnomeVFSMethodHandle *method_handle,
					 GnomeVFSFileOffset offset,
					 GnomeVFSFileSize size);

typedef GnomeVFSResult (* GnomeVFSMethodGetVolumeFreeSpaceFunc)
     					(GnomeVFSMethod *method,
					 const GnomeVFSURI *uri,
				 	 GnomeVFSFileSize *free_space);
</pre>
</div>
</div>
<div class="refsect1">
<a name="id2766570"></a><h2>Handling cancellation</h2>
<p>As VFS operations might take very long to complete, especially in the
    case of transient errors (such as a network server that has gone down),
    the GNOME Virtual File System Library provides a standard way to
    handle the cancellation of VFS operations.</p>
<div class="refsect2">
<a name="id2766583"></a><h3>The <span class="structname">GnomeVFSCancellation</span> object</h3>
<p>The object that encapsulates this functionality is
      <span class="structname">GnomeVFSCancellation</span>.  Most
      implementation functions get a pointer to such an object, and are
      expected to use this object to recognize when an operation should
      be interrupted.</p>
<p>The most simple way to check for a cancellation request is
      to poll the object with
      <code class="function">gnome_vfs_cancellation_check()</code>:</p>
<pre class="programlisting">
  
gboolean gnome_vfs_cancellation_check (GnomeVFSCancellation *cancellation);</pre>
<p>This function will return a nonzero value if the current
      operation should be cancelled.</p>
<p>Notice that cancellation is an asynchronous operation that
      might happen outside your function, in parallel with the code that
      you are writing.  For example, in the case of threads, the request
      will be set in the master thread; in the case of slave
      CORBA-driven processes, the request will be activated by a Unix
      signal.  So you can expect a cancellation request to happen (and
      consequently be signalled in
      <span class="structname">GnomeVFSCancellation</span>) at any time.</p>
<p>For this reason, you should be calling this function
      periodically, whenever you are going to perform several
      iterations of the same task, or execute a single expensive task.
      When the function returns a nonzero value, the correct way to
      react is:</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem"><p>Clean things up so that the result of the
        operations that have been performed are all
        cancelled.</p></li>
<li class="listitem"><p>Return the
        <span class="symbol">GNOME_VFS_ERROR_CANCELLED</span> error
        code.</p></li>
</ol></div>
<p>Note, there are some other situations in which you want to
      be able to interrupt an I/O operation when a cancellation request
      is performed.  In such cases, polling is not a viable option.</p>
<p>For this reason,
      <span class="structname">GnomeVFSCancellation</span> provides an
      alternative way of sending notifications, using a file
      descriptor.  To use this feature, you should use the following
      function:</p>
<pre class="programlisting">

gint gnome_vfs_cancellation_get_fd (GnomeVFSCancellation *cancellation); </pre>
<p>When this function is called, it will return an open file
      descriptor, which is the read-side of a pipe.  The pipe will be
      given a character from the write side as soon as a cancellation
      request is sent.  You can check for a cancellation by using the 
      <code class="function">select()</code> system call with this file descriptor.
      As soon as <code class="function">select</code> reports that some
      data is available on this file descriptor, you know that a
      cancellation is being requested.</p>
<p>For example, if you are reading from a file descriptor and
      you want to check for a pending cancellation at the same time,
      you can set up <code class="function">select</code>for checking if data
      is available on both the cancellation file descriptor and the
      file descriptor you are reading from.</p>
</div>
<hr>
<div class="refsect2">
<a name="id2766737"></a><h3>Dealing with <span class="symbol">EINTR</span>
</h3>
<p>In order to maximize the chance of cancelling an operation
      immediately, the GNOME Virtual File System can sends a signal to
      the asynchronous thread or process.  This does not happen on all
      the systems and setups, though.</p>
<p>The result of this is that, if a process is in the middle
      of a Unix system call while receiving this signal, the system
      call might be interrupted and return a <span class="symbol">EINTR</span>
      error.</p>
<p>For this reason, when you receive <span class="symbol">EINTR</span>
      you should check if a cancellation request is pending, using
      <code class="function">gnome_vfs_cancellation_check()</code> on the
      <span class="structname">GnomeVFSCancellation</span> object that the
      implementation function received:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem"><p>If a cancellation is indeed pending
        (<code class="function">gnome_vfs_cancellation_check()</code> returns a
        nonzero value), you should cancel the operation, cleaning up
        all the effects, and return
        <span class="symbol">GNOME_VFS_ERROR_INTERRUPTED</span> or
        <span class="symbol">GNOME_VFS_ERROR_CANCELLED</span></p></li>
<li class="listitem"><p>Otherwise, retry the system call as you would
        normally do.</p></li>
</ul></div>
</div>
</div>
<div class="refsect1">
<a name="id2766813"></a><h2>Basic guidelines for writing a module</h2>
<p>Writing GNOME VFS modules is easy, but there are a few
    things that you must keep in mind when hacking them:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem"><p>All of the code must be completely thread safe.
      The reason for this is that the asynchronous GNOME VFS engine
      will use threads when available; if you don't make sure that the
      code is thread-safe, every kind of weird and unexpected errors
      will happen.  As debugging these problems can be very hard, it's
      important to write the code with threads in mind right from the
      start.</p></li>
<li class="listitem"><p>Use the special
      <code class="function">gnome_vfs_*_cancellable()</code> VFS functions
      instead of the standard non-cancellable ones, passing them the
      same <span class="structname">GnomeVFSCancellation</span> object you
      are given, so that the operation can always be interrrupted at
      any time.</p></li>
<li class="listitem"><p>The code should respect the basic GNOME
      guidelines for source code indentation and
      style.</p></li>
</ul></div>
<div class="refsect2">
<a name="id2766863"></a><h3>How to make the code thread safe</h3>
<p>Although it might sound scary at first, making the code
      for the modules thread safe is not complicated at all.</p>
<p>First of all, make sure the amount of global variables is
      kept to the bare minimum.  If possible, you should avoid them at
      all cost.</p>
<p>For those cases where globals are inevitable (such as
      caches, connection pools or things like that), you have to make
      sure every variable is properly associated with a mutex, and
      that the mutex is locked before every access to this variable
      and released afterwards.  You can also use
      <code class="function">G_LOCK_DEFINE_STATIC</code>,
      <code class="function">G_LOCK</code> and <code class="function">G_UNLOCK</code>
      for this.
      </p>
<p>Generally speaking, if you are going to dynamically
      allocate structures that are shared by more than one
      operation/file, you should provide all of them with their nice
      mutex locks.</p>
<p>Finally, make sure mutexes are used only if they are
      available.  One way to do so is to use macros like the
      following:</p>
<pre class="programlisting">

#ifdef G_THREADS_ENABLED
#define MUTEX_NEW()     g_mutex_new ()
#define MUTEX_FREE(a)   g_mutex_free (a)
#define MUTEX_LOCK(a)   if ((a) != NULL) g_mutex_lock (a)
#define MUTEX_UNLOCK(a) if ((a) != NULL) g_mutex_unlock (a)
#else
#define MUTEX_NEW()     NULL
#define MUTEX_FREE(a)
#define MUTEX_LOCK(a)
#define MUTEX_UNLOCK(a)
#endif</pre>
<p><code class="function">G_LOCK_DEFINE_STATIC</code>,
      <code class="function">G_LOCK</code> and <code class="function">G_UNLOCK</code> in
      GLib are always safe to use, as they are already defined to be
      nothing when thread support is not available.</p>
<p>(Probably it would be a good idea to have something in the
      private GNOME VFS API that does this stuff for all the
      modules.)</p>
</div>
</div>
</div>
<div class="footer">
<hr>
          Generated by GTK-Doc V1.15.1</div>
</body>
</html>